package com.logistics.modules.transportationManagement.service.impl;

import cn.hutool.core.convert.Convert;
import com.logistics.common.utils.R;
import com.logistics.modules.financialManagement.dao.FreightDao;
import com.logistics.modules.transportationManagement.chart.KeyAndValueChart;
import com.logistics.modules.transportationManagement.chart.VehicleOrderByYear;
import com.logistics.modules.transportationManagement.dao.MoveplanDao;
import com.logistics.modules.transportationManagement.dao.MoveplandetailsDao;
import com.logistics.modules.transportationManagement.entity.*;
import com.logistics.modules.transportationManagement.service.MoveplanService;
import com.logistics.modules.transportationManagement.service.VehiclemoveorderdetailsService;
import com.logistics.modules.vehicleManagement.dao.VehicleDao;
import com.logistics.modules.vehicleManagement.entity.VehicleEntity;
import com.logistics.modules.warehouseManagement.dao.SeatDao;
import com.logistics.modules.warehouseManagement.entity.SeatEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.logistics.common.utils.PageUtils;
import com.logistics.common.utils.Query;

import com.logistics.modules.transportationManagement.dao.VehiclemoveorderDao;
import com.logistics.modules.transportationManagement.service.VehiclemoveorderService;
import org.springframework.transaction.annotation.Transactional;


/**
 * impl vehiclemoveorder服务
 *
 * @author 水穷处云起时
 * @date 2022/05/17
 */
@Service("vehiclemoveorderService")
public class VehiclemoveorderServiceImpl extends ServiceImpl<VehiclemoveorderDao, VehiclemoveorderEntity> implements VehiclemoveorderService {


    @Autowired
    private VehicleDao vehicleDao;

    @Autowired
    private MoveplanDao moveplanDao;

    @Autowired
    private MoveplanService moveplanService;

    @Autowired
    private MoveplandetailsDao moveplandetailsDao;

    @Autowired
    private SeatDao seatDao;

    @Autowired
    private VehiclemoveorderdetailsService vehiclemoveorderdetailsService;

    @Autowired
    private FreightDao freightDao;



    /**
     * 查询页面
     *
     * @param params 参数个数
     * @return {@link PageUtils}
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<VehiclemoveorderEntity> page = new Query<VehiclemoveorderEntity>().getPage(params);

        // 获取参数
        String vehicleName = Convert.toStr(params.get("vehicleName"));
        Integer vehicleTypeId = Convert.toInt(params.get("vehicleTypeId"));
        String startAddress = Convert.toStr(params.get("startAddress"));
        String endAddress = Convert.toStr(params.get("endAddress"));
        Integer transportationStatus = Convert.toInt(params.get("transportationStatus"));

        // 携带参数去数据库进行分页查询
        this.baseMapper.quaryPage(page, vehicleName, vehicleTypeId, startAddress, endAddress,transportationStatus);

        return new PageUtils(page);
    }

    /**
     * 生成运输订单
     *
     * @param params 参数个数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateShippingOrder(Map<String, Object> params) {
        // 1.获取参数
        // 运输计划id集合
        String movePlanIds1 = params.get("movePlanIds").toString();
        String[] split = movePlanIds1.replaceAll("\"","").split(",");
        Integer[] movePlanIds = Convert.toIntArray(split);
        // 通过运输订单ids去数据库批量拿到数据
        List<MoveplanEntity> movePlans = moveplanDao.selectAllByIds(movePlanIds);
        // 选中的车辆id
        Integer vehicleId = Convert.toInt(params.get("vehicleId"));

        // 2. 去数据库中拿到要生成的数据
        MoveplanEntity movePlan = moveplanDao.selectOneById(movePlanIds[0]);
        // 实体类的各个数据
        String startAddress = movePlan.getClientOrder().getStartAddress();
        String endAddress = movePlan.getClientOrder().getEndAddress();
        Date startTime = new Date();
        // 获取运输订单总金额
        Double totalMoney = getTheTotalAmountOfTheShippingOrder(movePlans);

        // 3. 实例化车辆订单
        VehiclemoveorderEntity vehiclemoveorderEntity =
                new VehiclemoveorderEntity(vehicleId, startAddress, endAddress, startTime, totalMoney, 0);

        // 4. 保存到数据库
        this.save(vehiclemoveorderEntity);

        // 5. 生成车辆订单详情 并保存到数据库
        generateVehicleDetails(vehiclemoveorderEntity, movePlans);

        // 6. 修改运输计划中的货物状态为已装车
        updateMovePlanCargoStatusByIds(movePlanIds);

        // 7. 修改车辆状态为已占用
        updateVehicleStatusById(vehicleId);

        // 8. 释放席位的占用状态 释放席位的货物和货物保存时间
        freedSeatOccupyStatus(movePlans);

        // 9. 设置运费表中的车辆
        modifyVehiclesInShipping(movePlans, vehicleId);
    }


    /**
     * 更新车辆和移动状态
     * @param params
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateVehicleAndMoveOfStatus(Map<String, Object> params) {
        // 车辆运输订单id
        Integer id = Convert.toInt(params.get("id"));
        // 要修改为的状态
        Integer status = Convert.toInt(params.get("status"));
        // 根据id修改车辆运输状态为运输中
        this.baseMapper.updateStatusById(status,id);
        VehiclemoveorderEntity vehiclemoveorderEntity = this.baseMapper.selectOneById(id);
        // 修改运输计划的状态
        Boolean res = moveplanService.modifyTheStatusOfAShippingPlan(vehiclemoveorderEntity,status);
        //
        if (!res) {
            throw new RuntimeException("更新车辆和移动状态失败!");
        }
    }

    /**
     * 查询页面列表状态
     *
     * @param params 参数个数
     * @return {@link PageUtils}
     */
    @Override
    public PageUtils queryPageListByStatus(Map<String, Object> params) {
        IPage<VehiclemoveorderEntity> page = new Query<VehiclemoveorderEntity>().getPage(params);

        // 获取参数
        String vehicleName = Convert.toStr(params.get("vehicleName"));
        Integer vehicleTypeId = Convert.toInt(params.get("vehicleTypeId"));
        String startAddress = Convert.toStr(params.get("startAddress"));
        String endAddress = Convert.toStr(params.get("endAddress"));

        // 携带参数去数据库进行分页查询
        this.baseMapper.queryPageListByStatus(page, vehicleName, vehicleTypeId, startAddress, endAddress);

        return new PageUtils(page);
    }

    /**
     * 实现车辆运输订单的入库操作
     *
     * @param params 参数个数
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void ruku(Map<String, Object> params) {
        // 获取参数
        Integer vehicleMoveOrderId = Convert.toInt(params.get("vehicleMoveOrderId"));
        Integer storehouse = Convert.toInt(params.get("storehouse"));
        // 效验
        if (storehouse == null || vehicleMoveOrderId == null) {
            throw new RuntimeException("车辆运输订单在[入库]中检查到参数为空请联系管理员!");
        }

        // 1. 修改车辆运输订单 设置完成时间 状态为已完成
        updateVehicleByStatusAndSetTime(vehicleMoveOrderId);
        // 2. 修改运输计划的状态 待取货
        updateMovePlanCargoStatus(vehicleMoveOrderId);
        // 3. 把车辆运输订单中的货物保存到仓库中 设置货物id 设置保存时间 修改状态
        saveTheGoodsAccordingToTheVehicleTransportOrderId(vehicleMoveOrderId, storehouse);
        // 4. 释放车辆的状态
        theStateOfTheReleasedVehicle(vehicleMoveOrderId);
    }

    /**
     * 添加总里程
     *
     * @param params 参数个数
     */
    @Override
    public void addTotalMileage(Map<String, Object> params) {
        // 获取参数
        Integer id = Convert.toInt(params.get("id"));
        Double totalMileage = Convert.toDouble(params.get("totalMileage"));

        // 效验
        if (id == null || totalMileage == null) {
            // 抛出异常
            throw new RuntimeException("参数为空!");
        }

        // 添加总里程
        Integer result = this.baseMapper.updateTotalMileageById(totalMileage, id);

        // 效验
        if (result == 0) {
            // 抛出异常
            throw new RuntimeException("添加总里程失败!");
        }
    }

    /**
     * 获得统计数据
     *
     * @return {@link R}
     */
    @Override
    public R getStatisticsData() {
        // 1. 实例化集合
        List<String> names = new ArrayList<>();
        List<String> values = new ArrayList<>();
        List<KeyAndValueChart> keyAndValueCharts = this.baseMapper.selectTotalMileageByVehicleNumber();
        for (KeyAndValueChart keyAndValueChart : keyAndValueCharts) {
            names.add(keyAndValueChart.getName());
            values.add(keyAndValueChart.getValue());
        }
        // 2. 返回
        return R.ok().put("names", names).put("values", values);
    }

    /**
     * 获得统计数据 年
     *
     * @return {@link R}
     */
    @Override
    public R getStatisticsDataByYear() {
        // 1. 拿到所有的车牌号
        ArrayList<String> licensePlateNumberCollection = new ArrayList<>();
        List<VehicleEntity> vehicleEntities = vehicleDao.selectList(null);
        for (VehicleEntity vehicleEntity : vehicleEntities) {
            licensePlateNumberCollection.add(vehicleEntity.getLicenseNumber());
        }
        // 2. 拿到车辆运输订单所有的月份
        List<String> monthCollection = this.baseMapper.selectMonth();
        monthCollection = monthCollection.stream().map(month -> {
            return month + "月";
        }).collect(Collectors.toList());
        // 3. 实例化集合
        ArrayList<VehicleOrderByYear> vehicleOrderByYears = new ArrayList<>();
        // 4. 根据车牌号查询数据
        for (String license : licensePlateNumberCollection) {
            // 4.1 拿到每个车牌号的数据
            List<String> strings = this.baseMapper.selectMonthMileageByVehicleNumber(license);
            // 4.2 实例化
            VehicleOrderByYear vehicleOrderByYear = new VehicleOrderByYear(license, strings);
            // 4.3 添加到集合中
            vehicleOrderByYears.add(vehicleOrderByYear);
        }

        // 5. 返回
        return R.ok().put("vehicleOrderByYears", vehicleOrderByYears).
                put("months", monthCollection).
                put("licensePlateNumbers", licensePlateNumberCollection);
    }


    /**
     * 释放座位占据地位
     *
     * @param movePlans 行动计划
     */
    private void freedSeatOccupyStatus(List<MoveplanEntity> movePlans) {
        // 拿到所有的seat
        for (MoveplanEntity movePlan : movePlans) {
            List<MoveplandetailsEntity> moveplandetailsEntities = moveplandetailsDao.selectAllByMoveplanId(movePlan.getId());
            for (MoveplandetailsEntity moveplandetailsEntity : moveplandetailsEntities) {
                seatDao.updateSeatStatusById(0, moveplandetailsEntity.getSeatId());
                seatDao.updateCargoSaveSeatById(moveplandetailsEntity.getSeatId());
                seatDao.updateCargoIdById(moveplandetailsEntity.getSeatId());
            }
        }
    }

    /**
     * 根据id更新车辆状态
     *
     * @param vehicleId 车辆标识
     */
    private void updateVehicleStatusById(Integer vehicleId) {
        // 把车辆的状态更改为已占用 0
        vehicleDao.updateVehicleStatusById(0, vehicleId);
    }

    /**
     *  修改运输计划中的货物状态
     *
     * @param movePlanIds 行动计划id
     */
    private void updateMovePlanCargoStatusByIds(Integer[] movePlanIds) {
        // 循环遍历修改运输计划的货物状态为 1: 已装车
        for (int i = 0; i < movePlanIds.length; i++) {
            moveplanDao.updateCargoStatusById(1, movePlanIds[i]);
        }
    }

    /**
     * 生成车辆细节
     *  @param vehiclemoveorderEntity vehiclemoveorder实体
     * @param movePlans
     */
    private void generateVehicleDetails(VehiclemoveorderEntity vehiclemoveorderEntity, List<MoveplanEntity> movePlans) {
        // 车辆运输订单详情集合 用于批量插入
        List<VehiclemoveorderdetailsEntity> detailsList = new ArrayList<>();

        // 1. 通过运输订单ids去数据库批量拿到数据

        // 2. 把每一条运输记录生成车辆运输订单详情
        for (MoveplanEntity movePlan : movePlans) {
            VehiclemoveorderdetailsEntity vehiclemoveorderdetailsEntity = new VehiclemoveorderdetailsEntity
                            (vehiclemoveorderEntity.getId(), movePlan.getId(), movePlan.getFreight().getCargoMoeny());
            detailsList.add(vehiclemoveorderdetailsEntity);
        }
        // 3. 批量插入到数据库中
        boolean result = vehiclemoveorderdetailsService.saveBatch(detailsList);

        // 4. 检查
        if (!result) {
            throw new RuntimeException("车辆运输订单详情添加失败!");
        }
    }

    /**
     * 获取运输订单总金额
     *
     * @param movePlans 行动计划id
     * @return {@link Double}
     */
    private Double getTheTotalAmountOfTheShippingOrder(List<MoveplanEntity> movePlans) {
        // 1. 声明总金额
        Double totalMonty = 0.0;
        // 2. 通过运输订单ids去数据库批量拿到数据
        // 3. 循环遍历统计总金额
        for (MoveplanEntity movePlan : movePlans) {
            totalMonty = totalMonty + movePlan.getFreight().getCargoMoeny();
        }
        // 4. 返回
        return totalMonty;
    }

    /**
     * 设置运费表中的车辆
     *
     * @param movePlans 行动计划
     * @param vehicleId 车辆标识
     */
    private void modifyVehiclesInShipping(List<MoveplanEntity> movePlans, Integer vehicleId) {
        // 循环遍历
        for (MoveplanEntity movePlan : movePlans) {
            // 根据运费表id 设置车辆
            freightDao.updateVehicleIdById(vehicleId, movePlan.getFrightId());
        }
    }

    /**
     * 更新车辆状态和设置时间
     *
     * @param vehicleMoveOrderId 车辆移动订单id
     */
    private void updateVehicleByStatusAndSetTime(Integer vehicleMoveOrderId) {
        // 1. 实例化对象
        VehiclemoveorderEntity vehiclemoveorderEntity = new VehiclemoveorderEntity();
        // 2. 设置参数
        vehiclemoveorderEntity.setId(vehicleMoveOrderId);
        // 设置状态 为已完成
        vehiclemoveorderEntity.setStatus(3);
        // 设置完成时间
        vehiclemoveorderEntity.setReachTime(new Date());

        // 3. 保存数据库中
        this.baseMapper.updateSelective(vehiclemoveorderEntity);
    }

    /**
     * 更新行动计划货物状态
     *
     * @param vehicleMoveOrderId 车辆移动订单id
     */
    private void updateMovePlanCargoStatus(Integer vehicleMoveOrderId) {
        // 1. 根据id拿到<<车辆运输订单详情>> 集合
        List<VehiclemoveorderdetailsEntity> detailsList =
                vehiclemoveorderdetailsService.selectAllByVehicleMoveOrderId(vehicleMoveOrderId);
        // 2. 遍历集合 用movePlanId 更新货物的状态为待取货
        for (VehiclemoveorderdetailsEntity vod : detailsList) {
            moveplanDao.updateCargoStatusById(4, vod.getMoveplanId());
        }
    }

    /**
     * 保存货物根据车辆运输订单id
     *
     * @param vehicleMoveOrderId 车辆移动订单id
     * @param storehouse         仓库
     */
    private void saveTheGoodsAccordingToTheVehicleTransportOrderId(
            Integer vehicleMoveOrderId, Integer storehouse) {
        // 1. 根据 vehicleMoveOrderId 拿到 vehicleMoveOrderDetailsList
        List<VehiclemoveorderdetailsEntity> vehicleMoveOrderDetailsList = vehiclemoveorderdetailsService.selectAllByVehicleMoveOrderId(vehicleMoveOrderId);
        // 2. 根据 vehicleMoveOrderDetailsList 和 storehouse 保存货物到席位
        saveIntoSeatsBasedOnCollectionAndWarehouseId(vehicleMoveOrderDetailsList, storehouse);
    }

    /**
     * 根据 vehicleMoveOrderDetailsList 和 storehouse 保存货物到席位
     *
     * @param vehicleMoveOrderDetailsList 车辆移动订单详细信息列表
     * @param storehouse                  仓库
     */
    private void saveIntoSeatsBasedOnCollectionAndWarehouseId(List<VehiclemoveorderdetailsEntity> vehicleMoveOrderDetailsList, Integer storehouse) {
        // 遍历车辆订单详情集合
        for (VehiclemoveorderdetailsEntity vmo : vehicleMoveOrderDetailsList) {
            // 遍历运输计划详情集合
            for (MoveplandetailsEntity mp : vmo.getMovePlan().getMovePlanDetailsList()) {
                // 根据这个货物类型id取数据库中匹配到一个席位
                SeatEntity seat = seatDao.selectOneByCargoTypeIdAndRepositoryId(mp.getCargo().getCargoTypeId(), storehouse);
                // 设置id
                seat.setCargoId(mp.getCargo().getId());
                // 设置保存的时间
                seat.setCargoSaveSeat(new Date());
                // 设置仓席位的状态
                seat.setSeatStatus(1);
                // 修改席位的状态
                seatDao.updateSelective(seat);
                // 修改运输计划详情的席位
                mp.setSeatId(seat.getId());
                // 保存到运输计划详情里
                moveplandetailsDao.updateSeatIdById(seat.getId(), mp.getId());
            }
        }
    }


    /**
     * 发布车辆的状态
     *
     * @param vehicleMoveOrderId 车辆移动订单id
     */
    private void theStateOfTheReleasedVehicle(Integer vehicleMoveOrderId) {
        // 1. 拿到 车辆运输订单实体类
        VehiclemoveorderEntity vehiclemoveorderEntity = this.baseMapper.selectOneById(vehicleMoveOrderId);
        // 2. 根据车辆id修改状态
        vehicleDao.updateVehicleStatusById(1, vehiclemoveorderEntity.getVehicleId());
    }

}